Skip to content

16 copy拷贝操作

Python中赋值操作不会复制对象,只是创建了一个新的引用。修改新变量,原变量也会跟着变——这是很多Bug的根源。copy模块就是解决这个问题的。

一、赋值 vs 拷贝

1.1 赋值只是引用

python
a = [1, 2, 3]
b = a  # 赋值,b和a指向同一个对象

b.append(4)
print(a)  # [1, 2, 3, 4](a也变了)
print(a is b)  # True(同一个对象)

1.2 浅拷贝:copy()

python
import copy

a = [1, 2, 3]
b = copy.copy(a)  # 浅拷贝

b.append(4)
print(a)  # [1, 2, 3](a不受影响)
print(a is b)  # False(不同对象)

1.3 深拷贝:deepcopy()

python
import copy

a = [[1, 2], [3, 4]]
b = copy.copy(a)      # 浅拷贝
c = copy.deepcopy(a)  # 深拷贝

b[0].append(999)
print(a)  # [[1, 2, 999], [3, 4]](a受影响,因为浅拷贝只复制了外层)

c[0].append(888)
print(a)  # [[1, 2, 999], [3, 4]](a不受影响,深拷贝递归复制了所有层)

二、浅拷贝 vs 深拷贝

2.1 区别

操作外层对象内层对象
赋值共享共享
浅拷贝新建共享
深拷贝新建新建

2.2 图解

python
import copy

original = [[1, 2], [3, 4]]

# 浅拷贝
shallow = copy.copy(original)
# shallow[0] 和 original[0] 是同一个对象

# 深拷贝
deep = copy.deepcopy(original)
# deep[0] 和 original[0] 是不同对象

三、哪些操作是浅拷贝

3.1 列表的浅拷贝方式

python
a = [1, 2, 3]

# 以下都是浅拷贝
b = a.copy()
b = a[:]
b = list(a)
b = copy.copy(a)

3.2 字典的浅拷贝方式

python
d = {"a": 1, "b": [2, 3]}

# 以下都是浅拷贝
d2 = d.copy()
d2 = dict(d)
d2 = copy.copy(d)

3.3 集合的浅拷贝方式

python
s = {1, 2, 3}

s2 = s.copy()
s2 = copy.copy(s)

四、深拷贝的使用场景

4.1 嵌套可变对象

python
import copy

# 配置模板
config_template = {
    "database": {"host": "localhost", "port": 5432},
    "features": ["auth", "logging"]
}

# 创建独立的配置副本
config1 = copy.deepcopy(config_template)
config2 = copy.deepcopy(config_template)

config1["database"]["host"] = "192.168.1.100"
config2["features"].append("cache")

# 原模板不受影响
print(config_template)
# {'database': {'host': 'localhost', 'port': 5432}, 'features': ['auth', 'logging']}

4.2 函数参数保护

python
import copy

def process_data(data):
    # 深拷贝,避免修改原数据
    data = copy.deepcopy(data)
    data["processed"] = True
    return data

original = {"name": "大志", "scores": [90, 85, 92]}
result = process_data(original)

print(original)  # {'name': '大志', 'scores': [90, 85, 92]}
print(result)    # {'name': '大志', 'scores': [90, 85, 92], 'processed': True}

4.3 备份状态

python
import copy

class GameState:
    def __init__(self):
        self.position = [0, 0]
        self.inventory = []
        self.health = 100

    def save(self):
        return copy.deepcopy(self)

    def restore(self, state):
        self.__dict__.update(state.__dict__)

game = GameState()
game.inventory.append("sword")

# 保存状态
saved = game.save()

game.inventory.append("shield")
game.health = 50

# 恢复状态
game.restore(saved)
print(game.inventory)  # ['sword']
print(game.health)     # 100

五、自定义拷贝行为

5.1 copy__和__deepcopy

python
import copy

class MyObject:
    def __init__(self, data, cache):
        self.data = data
        self.cache = cache  # 缓存不需要拷贝

    def __copy__(self):
        # 浅拷贝:只拷贝data,cache共享
        new = self.__class__.__new__(self.__class__)
        new.data = self.data
        new.cache = self.cache
        return new

    def __deepcopy__(self, memo):
        # 深拷贝:data递归拷贝,cache共享
        new = self.__class__.__new__(self.__class__)
        memo[id(self)] = new
        new.data = copy.deepcopy(self.data, memo)
        new.cache = self.cache  # 缓存共享
        return new

5.2 不可拷贝的对象

python
import copy

# 某些对象不能拷贝
import threading
lock = threading.Lock()

try:
    copy.deepcopy(lock)
except Exception as e:
    print(f"无法拷贝: {e}")

六、replace()函数(3.13+)

python
import copy

class Config:
    def __init__(self, host, port):
        self.host = host
        self.port = port

    def __replace__(self, **changes):
        new = self.__class__(self.host, self.port)
        new.__dict__.update(changes)
        return new

config = Config("localhost", 8080)
new_config = copy.replace(config, port=9090)

print(config.host, config.port)      # localhost 8080
print(new_config.host, new_config.port)  # localhost 9090

七、性能考虑

7.1 深拷贝的开销

python
import copy
import time

data = {"items": list(range(10000))}

# 浅拷贝快
start = time.perf_counter()
for _ in range(1000):
    copy.copy(data)
print(f"浅拷贝: {time.perf_counter() - start:.4f}秒")

# 深拷贝慢
start = time.perf_counter()
for _ in range(1000):
    copy.deepcopy(data)
print(f"深拷贝: {time.perf_counter() - start:.4f}秒")

深拷贝比浅拷贝慢很多,因为它要递归复制所有嵌套对象。

7.2 何时用哪种

场景用什么
对象只有一层copy()
对象有嵌套可变对象deepcopy()
不修改副本不需要拷贝
只读场景浅拷贝足够

八、实用技巧

8.1 安全地修改函数参数

python
import copy

def update_config(config, updates):
    result = copy.deepcopy(config)
    result.update(updates)
    return result

default = {"host": "localhost", "port": 8080}
custom = update_config(default, {"port": 9090})

print(default)  # {'host': 'localhost', 'port': 8080}
print(custom)   # {'host': 'localhost', 'port': 9090}

8.2 实现原型模式

python
import copy

class Prototype:
    def clone(self):
        return copy.deepcopy(self)

class Agent(Prototype):
    def __init__(self, name, config):
        self.name = name
        self.config = config

original = Agent("Agent-1", {"model": "gpt-5", "temp": 0.7})
clone = original.clone()

clone.name = "Agent-2"
clone.config["temp"] = 0.9

print(original.name)          # Agent-1
print(original.config['temp'])  # 0.7(不受影响)

九、总结

copy模块就两个核心函数:

函数用途
copy.copy()浅拷贝:外层新建,内层共享
copy.deepcopy()深拷贝:全部新建

选择原则:

  • 对象只有一层可变对象 → copy()
  • 对象有嵌套可变对象 → deepcopy()
  • 不确定 → deepcopy()更安全

记住:赋值不拷贝,浅拷贝只拷一层,深拷贝全拷